package elijah.base.dialog;

import android.content.Context;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.animation.AnimationUtils;
import android.widget.TextView;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewbinding.ViewBinding;

import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BasePopupView;
import com.lxj.xpopup.core.CenterPopupView;
import com.lxj.xpopup.interfaces.XPopupCallback;
import com.lxj.xpopup.util.XPopupUtils;

import java.util.List;

import elijah.base.R;
import elijah.base.adapter.BaseAdapter;
import elijah.base.databinding.BaseViewItemSingleSelectBinding;
import elijah.base.dialog.api.OnItemSingleSelectCallback;
import elijah.base.net.BaseResult;
import elijah.base.result.ListResult;
import elijah.base.utils.DensityUtils;
import elijah.base.utils.DialogUtils;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

public class BaseItemSingleSelectView<T, V extends ViewBinding> extends CenterPopupView {


    private Builder<T, V> builder;
    private BasePopupView dialog;
    private int page = 0;
    BaseViewItemSingleSelectBinding binding;
    private BaseAdapter<T, V> baseAdapter;

    private BaseItemSingleSelectView(@NonNull Context context) {
        super(context);
    }


    @Override
    protected int getImplLayoutId() {
        return R.layout.base_view_item_single_select;
    }

    @Override
    protected void onCreate() {
        super.onCreate();
        binding = BaseViewItemSingleSelectBinding.bind(getPopupImplView());
        buildView();
        getData(page = 0);


    }

    public BaseItemSingleSelectView<T, V> show(Builder<T, V> builder) {
        this.builder = builder;
        showDialog();
        return this;
    }

    private void getData(int page) {
        builder.getDataObservable().getData(binding.etSearch.getText().toString(), page)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseResult<ListResult<T>>(getContext(), false) {
                    @Override
                    public void onSubscribe(Disposable d) {
                        super.onSubscribe(d);
                        removeCallbacks(stopAnim);
                        binding.btRefresh.clearAnimation();
                        binding.btRefresh.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.rotate_anim));
                    }

                    @Override
                    public void onSuccess(ListResult<T> tListResult) {
                        postDelayed(stopAnim, 800);
                        super.onSuccess(tListResult);
                    }

                    @Override
                    public void onError(Throwable e) {
                        postDelayed(stopAnim, 800);
                        super.onError(e);
                    }

                    @Override
                    public void success(ListResult<T> tListResult) {
                        baseAdapter.setData(tListResult.getValues());
                        if (builder.getDataCallback() != null) {
                            builder.getDataCallback().onData(BaseItemSingleSelectView.this, tListResult.getValues());
                        }
                        binding.tvEmpty.setVisibility(tListResult.getValues().size() > 0 ? GONE : VISIBLE);
                    }
                });
    }

    public TextView getTitleTextView() {
        return binding.title;
    }

    private final Runnable stopAnim = () -> binding.btRefresh.clearAnimation();

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        removeCallbacks(stopAnim);
    }

    private void buildView() {

        binding.btClose.setOnClickListener(view -> DialogUtils.dismiss(dialog));
        binding.btRefresh.setOnClickListener(view -> getData(page));

        binding.title.setText(builder.getTitle());

        if (builder.getHeaderRes() > 0) {
            binding.headerContainer.addView(inflate(getContext(), builder.getHeaderRes(), null));
        } else {
            binding.headerContainer.setVisibility(GONE);
        }

        if (builder.backgroundColor > 0) {
            binding.getRoot().setCardBackgroundColor(builder.backgroundColor);
        }

        binding.btSearch.setVisibility(builder.isSearchable() ? VISIBLE : GONE);
        binding.etSearch.setVisibility(builder.isSearchable() ? VISIBLE : GONE);

        baseAdapter = builder.simpleAdapter != null ? builder.simpleAdapter : builder.getDataAdapter().getAdapter(BaseItemSingleSelectView.this);
        if (builder.getOnItemSingleSelectCallback() != null) {
            baseAdapter.setOnItemClickListener((view, position) -> {
                builder.getOnItemSingleSelectCallback().onSelect(baseAdapter.getItem(position), position);
                dialog.dismiss();
            });

        }
        binding.btAll.setVisibility(builder.getOnNothingSelectClickListener() != null ? VISIBLE : GONE);
        if (builder.getOnNothingSelectClickListener() != null) {
            binding.btAll.setOnClickListener(view -> {
                builder.getOnNothingSelectClickListener().onClick(view);
                dialog.dismiss();
            });
        }

        if (builder.getOnActionClickCallback() != null) {
            binding.btAction.setVisibility(VISIBLE);
            binding.btAction.setText(builder.getActionName());
            binding.btAction.setOnClickListener(v -> builder.getOnActionClickCallback().onAction(BaseItemSingleSelectView.this));
        }

        binding.recyclerView.setAdapter(baseAdapter);
        binding.recyclerView.setLayoutManager(builder.getLayoutManager() != null ? builder.getLayoutManager() : new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));
        if (builder.getLayoutManager() == null)
            binding.recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));
        binding.etSearch.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (TextUtils.isEmpty(s))
                    getData(page = 0);
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        binding.btSearch.setOnClickListener(view -> getData(page = 0));
        binding.btAdd.setVisibility(builder.getOnAddActionClickCallback() != null ? VISIBLE : GONE);
        binding.btAdd.setOnClickListener(view -> {
            if (builder.getOnAddActionClickCallback() != null) {
                builder.getOnAddActionClickCallback().onAction(this);
            }
        });

    }


    private void showDialog() {
        XPopup.Builder popupBuilder = new XPopup.Builder(getContext());
        popupBuilder
                .popupWidth(DensityUtils.getWidthPxRatio(builder.getViewWidth()))
                .popupHeight(builder.isAutoMinHeight() ? 0 : XPopupUtils.getScreenHeight(getContext()) - XPopupUtils.getStatusBarHeight() - XPopupUtils.getNavBarHeight())
                .autoDismiss(builder.isAutoDismiss())
                .dismissOnTouchOutside(builder.isAutoDismiss())
                .moveUpToKeyboard(false)
                .setPopupCallback(builder.popupCallback != null ? builder.popupCallback : new BasePopupCallback() {
                })
                .hasNavigationBar(false)
                .hasStatusBar(builder.isHasStatusBar())
        ;
        if (builder.getPopupConfig() != null) {
            builder.popupConfig.config(popupBuilder);
        }

        dialog = popupBuilder.asCustom(this)
                .show();
    }


    public static class Builder<T, V extends ViewBinding> {
        private final Context context;
        private String title;
        @IdRes
        private int headerRes;
        private float viewWidth = 0.5f;
        private boolean hasStatusBar;
        private BaseDialogView.PopupConfig popupConfig;
        private boolean searchable;
        private String actionName;
        private int backgroundColor;

        private boolean autoDismiss;
        private boolean autoMinHeight;
        private DataObservable<T> dataObservable;
        private DataAdapter<T, V> dataAdapter;
        private BaseAdapter<T, V> simpleAdapter;
        private RecyclerView.LayoutManager layoutManager;
        private OnItemSingleSelectCallback<T> onItemSingleSelectCallback;
        private OnAddActionClickCallback<T> onAddActionClickCallback;
        private OnActionClickCallback<T> onActionClickCallback;
        private OnClickListener onNothingSelectClickListener;
        private DataCallback<T> dataCallback;
        private XPopupCallback popupCallback;

        public int getBackgroundColor() {
            return backgroundColor;
        }

        public Builder<T, V> setBackgroundColor(int backgroundColor) {
            this.backgroundColor = backgroundColor;
            return this;
        }

        public boolean isHasStatusBar() {
            return hasStatusBar;
        }

        public Builder<T, V> setHasStatusBar(boolean hasStatusBar) {
            this.hasStatusBar = hasStatusBar;
            return this;
        }

        public BaseAdapter<T, V> getSimpleAdapter() {
            return simpleAdapter;
        }

        public Builder<T, V> setSimpleAdapter(BaseAdapter<T, V> simpleAdapter) {
            this.simpleAdapter = simpleAdapter;
            return this;
        }

        public DataAdapter<T, V> getDataAdapter() {
            return dataAdapter;
        }

        public Builder<T, V> setDataAdapter(DataAdapter<T, V> dataAdapter) {
            this.dataAdapter = dataAdapter;
            return this;
        }

        public XPopupCallback getPopupCallback() {
            return popupCallback;
        }

        public Builder<T, V> setPopupCallback(XPopupCallback popupCallback) {
            this.popupCallback = popupCallback;
            return this;
        }


        public DataCallback<T> getDataCallback() {
            return dataCallback;
        }

        public Builder<T, V> setDataCallback(DataCallback<T> dataCallback) {
            this.dataCallback = dataCallback;
            return this;
        }

        public boolean isAutoDismiss() {
            return autoDismiss;
        }

        public Builder<T, V> setAutoDismiss(boolean autoDismiss) {
            this.autoDismiss = autoDismiss;
            return this;
        }

        public boolean isAutoMinHeight() {
            return autoMinHeight;
        }

        public Builder<T, V> setAutoMinHeight(boolean autoMinHeight) {
            this.autoMinHeight = autoMinHeight;
            return this;
        }


        public OnClickListener getOnNothingSelectClickListener() {
            return onNothingSelectClickListener;
        }

        public Builder<T, V> setOnNothingSelectClickListener(OnClickListener onNothingSelectClickListener) {
            this.onNothingSelectClickListener = onNothingSelectClickListener;
            return this;
        }

        public RecyclerView.LayoutManager getLayoutManager() {
            return layoutManager;
        }

        public Builder<T, V> setLayoutManager(RecyclerView.LayoutManager layoutManager) {
            this.layoutManager = layoutManager;
            return this;
        }

        public OnItemSingleSelectCallback<T> getOnItemSingleSelectCallback() {
            return onItemSingleSelectCallback;
        }

        public Builder<T, V> setOnItemSingleSelectCallback(OnItemSingleSelectCallback<T> onItemSingleSelectCallback) {
            this.onItemSingleSelectCallback = onItemSingleSelectCallback;
            return this;
        }


        public OnAddActionClickCallback<T> getOnAddActionClickCallback() {
            return onAddActionClickCallback;
        }

        public Builder<T, V> setOnAddActionClickCallback(OnAddActionClickCallback<T> onAddActionClickCallback) {
            this.onAddActionClickCallback = onAddActionClickCallback;
            return this;
        }

        public Builder<T, V> setOnActionClickCallback(String actionName, OnActionClickCallback<T> onActionClickCallback) {
            this.onActionClickCallback = onActionClickCallback;
            this.actionName = actionName;
            return this;
        }

        public OnActionClickCallback<T> getOnActionClickCallback() {
            return onActionClickCallback;
        }

        public String getActionName() {
            return actionName;
        }

        public boolean isSearchable() {
            return searchable;
        }

        public Builder<T, V> setSearchable(boolean searchable) {
            this.searchable = searchable;
            return this;
        }


        public Builder(Context context) {
            this.context = context;
        }

        public BaseItemSingleSelectView<T, V> show() {
            return new BaseItemSingleSelectView<T, V>(context) {
            }.show(this);
        }


        public String getTitle() {
            return title;
        }

        public Builder<T, V> setTitle(String title) {
            this.title = title;
            return this;
        }

        public DataObservable<T> getDataObservable() {
            return dataObservable;
        }

        public Builder<T, V> setDataObservable(DataObservable<T> dataObservable) {
            this.dataObservable = dataObservable;
            return this;
        }

        public float getViewWidth() {
            return viewWidth;
        }

        public Builder<T, V> setViewWidth(float viewWidth) {
            this.viewWidth = viewWidth;
            return this;
        }


        public int getHeaderRes() {
            return headerRes;
        }

        public Builder<T, V> setHeaderRes(int headerRes) {
            this.headerRes = headerRes;
            return this;
        }

        public BaseDialogView.PopupConfig getPopupConfig() {
            return popupConfig;
        }

        public Builder<T, V> setPopupConfig(BaseDialogView.PopupConfig popupConfig) {
            this.popupConfig = popupConfig;
            return this;
        }
    }


    public interface DataObservable<T> {
        Single<ListResult<T>> getData(String key, int page);
    }

    public interface DataAdapter<T, V extends ViewBinding> {
        BaseAdapter<T, V> getAdapter(BaseItemSingleSelectView<T, V> baseView);
    }

    public interface OnAddActionClickCallback<T> {
        void onAction(BaseItemSingleSelectView<?, ?> baseView);
    }

    public interface OnActionClickCallback<T> {
        void onAction(BaseItemSingleSelectView<?, ?> baseView);
    }

    public void refreshData() {
        getData(page = 0);
    }

    public interface DataCallback<T> {
        void onData(BaseItemSingleSelectView<?, ?> view, List<T> values);
    }


}
